﻿using System;

/* 功能：当起床铃声响起，就引发学生起床/厨师做早餐两个事件 */

// 定义一个委托（也可以定义在Ring类里面）
public delegate void DoSomething();

// 产生事件的类
public class Ring
{
    // 声明一个委托事件
    public event DoSomething DoIt;

    // 构造函数
    public Ring()
    {

    }

    // 定义一个方法，即“响铃”，引发一个事件
    public void RaiseEvent()
    {
        Console.WriteLine("铃声响了......");

        // 判断事件是否有调用委托（是不是要求叫学生起床，叫厨师做饭）
        if(null != DoIt)
        {
            // 如果有注册的对象，那就调用委托（叫学生起床，叫厨师做饭）
            DoIt();
        }
        else
        {
            // 没有注册，事件没有调用任何委托
            Console.WriteLine("无事发生......");
        }
    }
}

// 学生类（处理事件类）
public class HandleEventOfStudents
{
    // 默认构造函数
    public HandleEventOfStudents()
    {

    }

    // 叫学生起床
    public void GetUp()
    {
        Console.WriteLine("[学生]：听到起床铃声响了，起床了。");
    }
}

// 校园厨师类（处理事件类二）
public class HandleEventOfChefs
{
    // 默认构造函数
    public HandleEventOfChefs()
    {

    }

    // 叫厨师做早餐
    public void Cook()
    {
        Console.WriteLine("[厨师]：听到起床铃声响了，为学生做早餐。");
    }
}

// 主类
public class ListenerEvent
{
    public static void Main(string[] args)
    {
        // 实例化一个铃声类[它是主角，都是因为它才牵连一系列的动作]
        Ring ring = new Ring();
        // 注册，学生委托铃声类，铃声响起的时候叫我起床.
        ring.DoIt += new HandleEventOfStudents().GetUp;
        // 注册，厨师告诉铃声类,我也委托你叫我什么时候做早餐
        ring.DoIt += new HandleEventOfChefs().Cook; //## MY IDEA ## ring.DoIt += new DoSomething(new HandleEventOfStudents().GetUp);
        // 铃声响起来了，它发现学生和厨师都拜托（注册）了自己，然后它就开始叫学生起床，叫厨师做早餐（一个事件调用了两个委托）
        ring.RaiseEvent();

        Console.ReadKey();
    }
}
/*
  你可能发现，上面的注册代码和前面的例子都不一样。这是因为 ring.doIt 本来就是 DoSomething 类型的，
C# 会自动把学生类方法转换成相同的类型（猜测，但是上面的代码可以完美运行）。当然上面的注册代码也可以写成和文章例子的一样。 
改成这样 ring.doIt += new Ring.DoSomething(new HandleEventOfStudents().GetUp); 
这样也可以实现，当然这样的话定义委托的语句就要写在 Ring 类里面了。
 */